<template>
  <div id="mainMap">
    <search-component @update-center="handleSearchUpdate" />
    <div id="container" style="width: 100%; height: calc(100% - 40px)"></div>
    <el-button class="clear-fence-btn" type="primary" @click="clearFence">清除围栏</el-button>
    <!-- 地图右键菜单 -->
    <div id="contextmenu_map" class="contextmenu_map">
      <div class="contextmenu_map_item" @click="addMarker(true)">添加坐标点</div>
    </div>
    <!-- Marker右键菜单 -->
    <div id="contextmenu_marker" class="contextmenu_marker">
      <div class="contextmenu_marker_item" @click="delMarkerFn">删除</div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { useScriptTag } from '@vueuse/core'
import { ElMessage } from 'element-plus'
import type { PropType } from 'vue'
import { onMounted, ref, watch } from 'vue'
import type { MapEvent } from '~/src/types/map'
import SearchComponent from './SearchComponent.vue'

defineOptions({
  name: 'MapComponent',
})

declare const T: any

interface Props {
  initialPoints?: string[]
  initialCenter?: { lat: number; lng: number }
}

const props = defineProps({
  initialPoints: {
    type: Array as PropType<string[]>,
    default: () => [],
  },
  initialCenter: {
    type: Object as PropType<{ lat: number; lng: number } | null>,
    default: null,
  },
})

interface FenceAssembly {
  TMapMarker: any[]
  latlngArr: string[]
  latlngStr: string
  polygon: any
  points?: any[]
}

const emits = defineEmits<{
  (e: 'update-center', center: { lat: number; lng: number }): void
  (e: 'update-fence-data', data: string[]): void
}>()

// 使用 useScriptTag 加载天地图 API
const { load } = useScriptTag('https://api.tianditu.gov.cn/api?v=4.0&tk=4c23f5e81bf0497296f2ff0e0bcb43c2')

const TMap = ref<any>(null)
const primaryColor = ref('#0249f9')

const addMarkerPos = ref<any>(null)
const delMarkerIndex = ref(-1)
const fenceAssembly = ref<FenceAssembly>({
  TMapMarker: [],
  latlngArr: [],
  latlngStr: '',
  polygon: null,
})

// 初始化地图
onMounted(() => {
  load().then(() => {
    initTMap()
  })
})

watch(
  () => props.initialPoints,
  (newPoints) => {
    if (TMap.value && newPoints && newPoints.length > 0) {
      console.log('[MapComponent] initialPoints changed, updating fence:', newPoints)
      fenceAssembly.value.latlngArr = [...newPoints]
      operateTMap()
    } else if (TMap.value && newPoints && newPoints.length === 0) {
      console.log('[MapComponent] initialPoints cleared, clearing fence.')
      clearFenceInternal()
    }
  },
  { deep: true, immediate: true }
)

function initTMap() {
  let center: any
  if (props.initialCenter) {
    center = new T.LngLat(props.initialCenter.lng, props.initialCenter.lat)
  } else if (props.initialPoints && props.initialPoints.length > 0) {
    const [firstLat, firstLng] = props.initialPoints[0].split(',').map(Number)
    if (!isNaN(firstLat) && !isNaN(firstLng)) {
      center = new T.LngLat(firstLng, firstLat)
    } else {
      center = new T.LngLat(84.885205, 45.575793)
    }
  } else {
    center = new T.LngLat(84.885205, 45.575793)
  }

  TMap.value = new T.Map('container')
  if (TMap.value) {
    TMap.value.centerAndZoom(center, 15)
    setupEditMode()
    if (!props.initialPoints || props.initialPoints.length === 0) {
      operateTMap()
    }
  }
}

function setupEditMode() {
  if (!TMap.value) return

  const checkAndAddMarker = (event: MapEvent, immediateAdd = false) => {
    if (fenceAssembly.value.latlngArr.length >= 20) {
      ElMessage({
        message: '电子围栏最多允许添加20个坐标点！',
        type: 'warning',
      })
      return
    }
    addMarkerPos.value = new T.LngLat(event.lnglat.lng, event.lnglat.lat)
    if (immediateAdd) {
      addMarker(true)
      contextmenuFn('')
    } else {
      contextmenuFn('map', event.containerPoint.x, event.containerPoint.y)
    }
  }

  TMap.value.addEventListener('click', (event: MapEvent) => {
    checkAndAddMarker(event, true)
  })

  TMap.value.addEventListener('contextmenu', (event: MapEvent) => {
    checkAndAddMarker(event)
  })
}

function operateTMap() {
  if (!TMap.value) return

  TMap.value.clearOverLays()
  const data = fenceAssembly.value.latlngArr

  fenceAssembly.value.TMapMarker.forEach((marker) => {
    marker.removeEventListener('dragend')
    marker.removeEventListener('contextmenu')
  })
  fenceAssembly.value.TMapMarker = []

  data.forEach((ele) => {
    const [lat, lng] = ele.split(',').map(Number)
    if (!isNaN(lat) && !isNaN(lng)) {
      addMarkerPos.value = new T.LngLat(lng, lat)
      addMarker()
    }
  })

  const points = data.map((ele) => {
    const [lat, lng] = ele.split(',').map(Number)
    return new T.LngLat(lng, lat)
  })

  if (points.length > 0) {
    if (points.length >= 3) {
      console.log('[MapComponent] Drawing polygon and setting viewport for points:', points)
      fenceAssembly.value.points = points
      fenceAssembly.value.polygon = new T.Polygon(points, {
        color: primaryColor.value,
        weight: 3,
        opacity: 1,
        fillColor: '#44aaf8',
        fillOpacity: 0.3,
      })
      TMap.value.addOverLay(fenceAssembly.value.polygon)
      try {
        TMap.value.setViewport(points)
      } catch (error) {
        console.warn('[MapComponent] Error setting viewport for polygon, falling back to first point:', error)
        TMap.value.panTo(points[0], TMap.value.getZoom())
      }
    } else {
      console.log('[MapComponent] Less than 3 points, panning to first point:', points[0])
      TMap.value.panTo(points[0], TMap.value.getZoom() > 12 ? TMap.value.getZoom() : 12)
    }
  } else {
    console.log('[MapComponent] No points to draw or focus on.')
  }

  emits('update-fence-data', fenceAssembly.value.latlngArr)
}

function addMarker(isManualAdd = false) {
  if (!TMap.value || !addMarkerPos.value) return

  const markerIndex = fenceAssembly.value.TMapMarker.length

  generateTextImage(markerIndex + 1, (url: string) => {
    const icon = new T.Icon({
      iconUrl: url,
      iconAnchor: new T.Point(10, 10),
    })

    const marker = new T.Marker(addMarkerPos.value, { icon })
    fenceAssembly.value.TMapMarker.push(marker)

    TMap.value.addOverLay(marker)
    marker.enableDragging()

    marker.addEventListener('dragend', (event: MapEvent) => {
      const { lat, lng } = event.lnglat
      const latlngStr = `${lat},${lng}`
      fenceAssembly.value.latlngArr[markerIndex] = latlngStr
      fenceAssembly.value.latlngStr = fenceAssembly.value.latlngArr.join(';')
      operateTMap()
    })

    marker.addEventListener('contextmenu', (event: MapEvent) => {
      delMarkerIndex.value = markerIndex
      contextmenuFn('marker', event.containerPoint.x, event.containerPoint.y)
    })

    if (isManualAdd && addMarkerPos.value) {
      const { lat, lng } = addMarkerPos.value
      const latlngStr = `${lat},${lng}`
      fenceAssembly.value.latlngArr.push(latlngStr)
      fenceAssembly.value.latlngStr = fenceAssembly.value.latlngArr.join(';')
      contextmenuFn('')
      operateTMap()
    }
  })
}

function delMarkerFn() {
  fenceAssembly.value.latlngArr.splice(delMarkerIndex.value, 1)
  fenceAssembly.value.latlngStr = fenceAssembly.value.latlngArr.join(';')
  contextmenuFn('')
  operateTMap()
}

function generateTextImage(text: number, callback: (url: string) => void) {
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  if (!ctx) return

  canvas.width = 20
  canvas.height = 20
  ctx.beginPath()
  ctx.arc(10, 10, 10, 0, 2 * Math.PI)
  ctx.fillStyle = primaryColor.value
  ctx.fill()
  ctx.fillStyle = '#ffffff'
  ctx.font = '15px Arial'
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'
  ctx.fillText(text.toString(), canvas.width / 2, canvas.height / 1.8)
  const dataURL = canvas.toDataURL('image/png')
  callback(dataURL)
}

function contextmenuFn(mode = '', left?: number, top?: number) {
  const elements = {
    map: document.getElementById('contextmenu_map'),
    marker: document.getElementById('contextmenu_marker'),
  }

  if (mode && left != null && top != null) {
    const element = elements[mode as keyof typeof elements]
    if (element) {
      element.style.display = 'block'
      element.style.left = `${left}px`
      element.style.top = `${top}px`
    }
  }

  Object.entries(elements).forEach(([key, element]) => {
    if (key !== mode && element) {
      element.style.display = 'none'
    }
  })
}

function clearFenceInternal() {
  fenceAssembly.value.latlngArr = []
  fenceAssembly.value.latlngStr = ''
  fenceAssembly.value.TMapMarker = []
  fenceAssembly.value.polygon = null
  operateTMap()
}

function clearFence() {
  clearFenceInternal()
  emits('update-fence-data', [])
}

function setCenter(center: { lat: number; lng: number }) {
  if (TMap.value) {
    const newCenter = new T.LngLat(center.lng, center.lat)
    TMap.value.centerAndZoom(newCenter, 15)
  }
}

function setFencePoints(points: string[]) {
  fenceAssembly.value.latlngArr = points
  operateTMap()
}

const handleSearchUpdate = (center: { lat: number; lng: number }) => {
  console.log('[MapComponent] Received update-center from SearchComponent:', center)
  setCenter(center)
}

defineExpose({
  setCenter,
  setFencePoints,
})
</script>

<style scoped>
#mainMap {
  position: relative;
  width: 100%;
  height: 100%;
}

.clear-fence-btn {
  position: absolute;
  top: 50px;
  left: 10px;
  z-index: 400;
}

.tips {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2000;
}

.save {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2000;
}

.fenceItem {
  margin-bottom: 10px;
}

.h1Title {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: none;
}

.butBox {
  display: flex;
}

.mainRight {
  position: relative;
}

.but {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 400;
}

.contextmenu_map,
.contextmenu_polygon,
.contextmenu_marker {
  position: absolute;
  z-index: 1000;
  display: none;
  padding: 5px 0;
  background-color: #f9f9f9;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
}

.contextmenu_map_item,
.contextmenu_marker_item {
  padding: 10px 20px;
  cursor: pointer;
}

.contextmenu_map_item:hover,
.contextmenu_marker_item:hover {
  background-color: #f1f1f1;
}
</style>
